
package com.jf.cloud.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.auth.feign.AccountFeignClient;
import com.jf.cloud.api.auth.vo.AuthAccountVO;
import com.jf.cloud.api.leaf.feign.SegmentFeignClient;
import com.jf.cloud.api.product.bo.SpuSimpleBO;
import com.jf.cloud.api.product.dto.SkuStockLockDTO;
import com.jf.cloud.api.product.util.ProductLangUtil;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.constant.DistributedIdKey;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.product.constant.StockBillStatus;
import com.jf.cloud.common.product.constant.StockBillType;
import com.jf.cloud.common.product.constant.StockType;
import com.jf.cloud.common.product.dto.ProductSearchDTO;
import com.jf.cloud.common.product.dto.SkuDTO;
import com.jf.cloud.common.product.dto.SpuDTO;
import com.jf.cloud.common.product.vo.SkuVO;
import com.jf.cloud.common.product.vo.SpuVO;
import com.jf.cloud.common.product.vo.StockBillLogItemVO;
import com.jf.cloud.common.product.vo.StockBillLogVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.product.bo.mongo.MongoStockBillLogBO;
import com.jf.cloud.product.bo.mongo.MongoStockBillLogItemBO;
import com.jf.cloud.product.constant.ProdKeyType;
import com.jf.cloud.product.dto.StockBillLogDTO;
import com.jf.cloud.product.mapper.SkuMapper;
import com.jf.cloud.product.mapper.SkuStockMapper;
import com.jf.cloud.product.mapper.SpuExtensionMapper;
import com.jf.cloud.product.mapper.StockBillLogMapper;
import com.jf.cloud.product.model.*;
import com.jf.cloud.product.service.SkuService;
import com.jf.cloud.product.service.SkuStockService;
import com.jf.cloud.product.service.SpuService;
import com.jf.cloud.product.service.StockBillLogService;
import com.jf.cloud.product.vo.SkuExcelVO;
import com.jf.cloud.product.vo.StockBillLogExcelVO;
import com.jf.cloud.product.vo.StockBillLogItemExcelVO;
import com.jf.cloud.product.vo.mongo.MongoStockBillLogItemVO;
import com.jf.cloud.product.vo.mongo.MongoStockBillLogVO;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 出入库明细
 *
 * @author zz
 * @date 2022-06-22 16:57:26
 */
@Service
public class StockBillLogServiceImpl implements StockBillLogService {
    private final Logger logger = LoggerFactory.getLogger(StockBillLogServiceImpl.class);

    @Autowired
    private StockBillLogMapper stockBillLogMapper;
    @Autowired
    private MapperFacade mapperFacade;

    @Autowired
    private AccountFeignClient accountFeignClient;
    @Autowired
    private SegmentFeignClient segmentFeignClient;
    @Autowired
    private SkuStockMapper skuStockMapper;
    @Autowired
    private SpuExtensionMapper spuExtensionMapper;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private SpuService spuService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private SkuStockService skuStockService;
    @Value("${jfcloud.expose.operation.auth:}")
    private Boolean permission;

    @Override
    public PageVO<MongoStockBillLogBO> page(PageDTO pageDTO, StockBillLogDTO stockBillLogDTO) {
        // 主表查询条件
        Criteria logCriteria = getLogCriteria(stockBillLogDTO);
        // 主表返回字段
        ProjectionOperation logProjectionOperation = Aggregation.project("stockBillLogId", "stockBillNo", "sourceOrderNo", "stockBillType",
                "createTime", "updateTime", "stockChangeReasonId", "employeeId", "status", "businessTime",
                "totalCount", "totalAmount", "qualifications", "shopId", "supplierId", "remark", "type", "makerMobile");
        // 关联stockBillLogItem表
        LookupOperation lookupOperation = Aggregation.lookup("stock_bill_log_item", "_id", "stockBillLogId", "stockBillLogItems");
        // 展开联表字段
        UnwindOperation unwindOperation = Aggregation.unwind("stockBillLogItems");
        // 获取关联到stockBillLogItem的查询聚合条件
        Criteria itemCriteria = getItemCriteriaByParam(stockBillLogDTO);
        GroupOperation groupOperation = getGroupOperation();
        // 联表和主表返回字段
        ProjectionOperation allProjectionOperation =
                Aggregation.project("stockBillLogId", "stockBillNo", "sourceOrderNo", "stockBillType",
                "createTime", "updateTime", "stockChangeReasonId", "employeeId", "status", "businessTime",
                "totalCount", "totalAmount", "qualifications", "shopId", "supplierId", "remark", "type", "makerMobile");
        // 分组
        SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC, "createTime").and(Sort.Direction.DESC, "stockBillNo");
        // 分页数据
        SkipOperation skipOperation = Aggregation.skip((long) pageDTO.getPageSize() * (pageDTO.getPageNum() - 1));
        LimitOperation limitOperation = Aggregation.limit(pageDTO.getPageSize());
        TypedAggregation<MongoStockBillLogBO> typedAggregation = Aggregation.newAggregation(
                MongoStockBillLogBO.class,
                Aggregation.match(logCriteria),
                logProjectionOperation,
                lookupOperation,
                unwindOperation,
                Aggregation.match(itemCriteria),
                groupOperation,
                allProjectionOperation,
                sortOperation,
                skipOperation,
                limitOperation
        );
        logger.info("pageStockLog()的mongodb查询语句： {}", typedAggregation);
        // 执行聚合操作获取当前页数据
        AggregationResults<MongoStockBillLogBO> aggregationResults = mongoTemplate.aggregate(typedAggregation, MongoStockBillLogBO.class);
        // 总条数
        TypedAggregation<MongoStockBillLogBO> totalTypedAggregation = Aggregation.newAggregation(
                MongoStockBillLogBO.class,
                Aggregation.match(logCriteria),
                logProjectionOperation,
                lookupOperation,
                unwindOperation,
                Aggregation.match(itemCriteria),
                groupOperation,
                allProjectionOperation
        );
        AggregationResults<MongoStockBillLogBO> totalAggregationResults = mongoTemplate.aggregate(totalTypedAggregation, MongoStockBillLogBO.class);
        // 返回查询结果
        List<MongoStockBillLogBO> mappedResults = totalAggregationResults.getMappedResults();
        for(MongoStockBillLogBO mongoStockBillLogBO : mappedResults){
            if(BooleanUtil.isFalse(permission) && StrUtil.isNotBlank(mongoStockBillLogBO.getMakerMobile())){
                mongoStockBillLogBO.setMakerMobile(PhoneUtil.hideBetween(mongoStockBillLogBO.getMakerMobile()).toString());
            }
        }
        // 补充制单人名称
        Set<Long> employeeIds = mappedResults.stream().map(MongoStockBillLogBO::getEmployeeId).collect(Collectors.toSet());
        List<AuthAccountVO> accounts = accountFeignClient.listByUserIdsAndPhoneAndType(new ArrayList<>(employeeIds), null, SysTypeEnum.MULTISHOP.value()).getData();
        if (!CollectionUtils.isEmpty(accounts)) {
            Map<Long, String> userIdNameMap = accounts.stream().collect(Collectors.toMap(AuthAccountVO::getUserId, AuthAccountVO::getUsername));
            for (MongoStockBillLogBO mongoStockBillLogBO : mappedResults) {
                mongoStockBillLogBO.setMakerName(userIdNameMap.get(mongoStockBillLogBO.getEmployeeId()));
            }
        }
        // 构建分页数据
        PageVO<MongoStockBillLogBO> mongoStockBillLogPage = new PageVO<>();
        mongoStockBillLogPage.setTotal((long)mappedResults.size());
        mongoStockBillLogPage.setList(aggregationResults.getMappedResults());
        mongoStockBillLogPage.setPages(PageUtil.getPages(mappedResults.size(), pageDTO.getPageSize()));
        return mongoStockBillLogPage;
    }

    private GroupOperation getGroupOperation() {
        return Aggregation.group("stockBillLogId")
                .last("createTime").as("createTime")
                .last("stockBillNo").as("stockBillNo")
                .last("stockBillType").as("stockBillType")
                .last("updateTime").as("updateTime")
                .last("stockChangeReasonId").as("stockChangeReasonId")
                .last("employeeId").as("employeeId")
                .last("status").as("status")
                .last("businessTime").as("businessTime")
                .last("totalCount").as("totalCount")
                .last("totalAmount").as("totalAmount")
                .last("qualifications").as("qualifications")
                .last("shopId").as("shopId")
                .last("supplierId").as("supplierId")
                .last("remark").as("remark")
                .last("type").as("type")
                .last("makerMobile").as("makerMobile")
                .last("sourceOrderNo").as("sourceOrderNo");
    }

    @Override
    public MongoStockBillLogVO getByStockBillLogId(Long stockBillLogId) {
        MongoStockBillLogBO stockBillLogDb = mongoTemplate.findById(stockBillLogId, MongoStockBillLogBO.class);
        MongoStockBillLogVO mongoStockBillLogVO = mapperFacade.map(stockBillLogDb, MongoStockBillLogVO.class);
        Query query = new Query();
        query.addCriteria(Criteria.where("stockBillLogId").is(stockBillLogId));
        List<MongoStockBillLogItemBO> mongoStockBillLogItemList = mongoTemplate.find(query, MongoStockBillLogItemBO.class);
        // 处理商品信息
        List<MongoStockBillLogItemVO> mongoStockBillLogItemVOList = mapperFacade.mapAsList(mongoStockBillLogItemList, MongoStockBillLogItemVO.class);
        for (MongoStockBillLogItemVO mongoStockBillLogItemVO : mongoStockBillLogItemVOList) {
            SpuVO spu = spuService.getBySpuId(mongoStockBillLogItemVO.getSpuId());
            ProductLangUtil.spu(spu);
            mongoStockBillLogItemVO.setSpuName(spu.getName());
            mongoStockBillLogItemVO.setMeasureUnit(spu.getMeasureUnit());
            mongoStockBillLogItemVO.setMainImgUrl(spu.getMainImgUrl());
            SkuVO sku = skuService.getSkuBySkuId(mongoStockBillLogItemVO.getSkuId());
            mongoStockBillLogItemVO.setPartyCode(sku.getPartyCode());
            mongoStockBillLogItemVO.setImgUrl(sku.getImgUrl());
        }
        mongoStockBillLogVO.setStockBillLogItems(mongoStockBillLogItemVOList);
        return mongoStockBillLogVO;
    }

    @Override
    public List<StockBillLogExcelVO> exportStockBillLogList(StockBillLogDTO stockBillLogDTO) {
        // 主表查询条件
        Criteria logCriteria = getLogCriteria(stockBillLogDTO);
        // 主表返回字段
        ProjectionOperation logProjectionOperation = Aggregation.project("stockBillLogId", "stockBillNo", "sourceOrderNo", "stockBillType",
                "createTime", "updateTime", "stockChangeReasonId", "employeeId", "status", "businessTime",
                "totalCount", "totalAmount", "qualifications", "shopId", "supplierId", "remark", "type", "makerMobile");
        // 关联stockBillLogItem表
        LookupOperation lookupOperation = Aggregation.lookup("stock_bill_log_item", "_id", "stockBillLogId", "stockBillLogItems");
        // 展开联表字段
        UnwindOperation unwindOperation = Aggregation.unwind("stockBillLogItems");
        // 获取关联到stockBillLogItem的查询聚合条件
        Criteria itemCriteria = getItemCriteriaByParam(stockBillLogDTO);
        // 联表和主表返回字段
        ProjectionOperation allProjectionOperation =
                Aggregation.project("stockBillLogId", "stockBillNo", "sourceOrderNo", "stockBillType",
                        "createTime", "updateTime", "stockChangeReasonId", "employeeId", "status", "businessTime",
                        "totalCount", "totalAmount", "qualifications", "shopId", "supplierId", "remark", "type", "makerMobile", "stockBillLogItems");

        GroupOperation groupOperation = Aggregation.group("stockBillLogId")
                .first("stockBillLogId").as("stockBillLogId")
                .first("stockBillNo").as("stockBillNo")
                .first("sourceOrderNo").as("sourceOrderNo")
                .first("stockBillType").as("stockBillType")
                .first("createTime").as("createTime")
                .first("updateTime").as("updateTime")
                .first("stockChangeReasonId").as("stockChangeReasonId")
                .first("employeeId").as("employeeId")
                .first("status").as("status")
                .first("businessTime").as("businessTime")
                .first("totalCount").as("totalCount")
                .first("totalAmount").as("totalAmount")
                .first("qualifications").as("qualifications")
                .first("shopId").as("shopId")
                .first("supplierId").as("supplierId")
                .first("remark").as("remark")
                .first("type").as("type")
                .first("makerMobile").as("makerMobile")
                .addToSet("stockBillLogItems").as("stockBillLogItems")
                ;
        SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC, "createTime").and(Sort.Direction.DESC, "stockBillLogId");
        TypedAggregation<MongoStockBillLogBO> typedAggregation = Aggregation.newAggregation(
                MongoStockBillLogBO.class,
                Aggregation.match(logCriteria),
                logProjectionOperation,
                lookupOperation,
                unwindOperation,
                Aggregation.match(itemCriteria),
                allProjectionOperation,
                groupOperation,
                sortOperation
        );
        logger.info("exportStockBillLogList()的mongodb查询语句： {}", typedAggregation);
        // 执行聚合操作获取当前页数据
        AggregationResults<MongoStockBillLogVO> aggregationResults = mongoTemplate.aggregate(typedAggregation, MongoStockBillLogVO.class);
        List<MongoStockBillLogVO> mappedResults = aggregationResults.getMappedResults();
        List<Long> skuIds = new ArrayList<>();
        mappedResults.forEach(item -> {
            skuIds.addAll(item.getStockBillLogItems().stream().map(MongoStockBillLogItemVO::getSkuId).collect(Collectors.toList()));
        });
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSkuIds(skuIds);
        List<SkuExcelVO> skuList = skuService.exportSkuList(productSearchDTO);
        Map<Long, SkuExcelVO> skuMap = skuList.stream().collect(Collectors.toMap(SkuExcelVO::getSkuId, s -> s));
        // 补充制单人名称
        Set<Long> employeeIds = mappedResults.stream().map(MongoStockBillLogVO::getEmployeeId).collect(Collectors.toSet());
        List<AuthAccountVO> accounts = accountFeignClient.listByUserIdsAndPhoneAndType(new ArrayList<>(employeeIds), null, SysTypeEnum.MULTISHOP.value()).getData();
        Map<Long, String> userIdNameMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(accounts)) {
            userIdNameMap = accounts.stream().collect(Collectors.toMap(AuthAccountVO::getUserId, AuthAccountVO::getUsername));
        }
        for (MongoStockBillLogVO mongoStockBillLog : mappedResults) {
            if(BooleanUtil.isFalse(permission) && StrUtil.isNotBlank(mongoStockBillLog.getMakerMobile())){
                mongoStockBillLog.setMakerMobile(PhoneUtil.hideBetween(mongoStockBillLog.getMakerMobile()).toString());
            }
            for (MongoStockBillLogItemVO mongoStockBillLogItem : mongoStockBillLog.getStockBillLogItems()) {
                if (Objects.isNull(mongoStockBillLogItem.getSkuId())) {
                    continue;
                }
                if (!skuMap.containsKey(mongoStockBillLogItem.getSkuId())) {
                    continue;
                }
                SkuExcelVO skuExcel = skuMap.get(mongoStockBillLogItem.getSkuId());
                mongoStockBillLogItem.setSpuName(skuExcel.getSpuName());
                mongoStockBillLogItem.setSkuName(skuExcel.getSkuName());
                mongoStockBillLogItem.setPartyCode(skuExcel.getPartyCode());
            }
            mongoStockBillLog.setMakerName(userIdNameMap.get(mongoStockBillLog.getEmployeeId()));
        }


        return handleExportStockBillLogListInfo(mappedResults, stockBillLogDTO.getType());
    }

    private List<StockBillLogExcelVO> handleExportStockBillLogListInfo(List<MongoStockBillLogVO> stockBillLogList, Integer billType) {
        List<StockBillLogExcelVO> stockBillLogExcelList = mapperFacade.mapAsList(stockBillLogList, StockBillLogExcelVO.class);
        Map<Long, MongoStockBillLogVO> stockBillLogItemMap = stockBillLogList.stream().collect(Collectors.toMap(MongoStockBillLogVO::getStockBillLogId, item->item));
        for(StockBillLogExcelVO stockBillLogExcelVO : stockBillLogExcelList){
            String statusName = stockBillLogExcelVO.getStatus() == 1
                    ? (billType == 1 ? "出库" : "入库" )
                    : StockBillStatus.instance(stockBillLogExcelVO.getStatus()).text();
            stockBillLogExcelVO.setStockBillTypeName(StockBillType.instance(stockBillLogExcelVO.getStockBillType()).text());
            stockBillLogExcelVO.setStatusName(StockBillStatus.instance(stockBillLogExcelVO.getStatus()).text());
            stockBillLogExcelVO.setSkuName(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getStockBillLogItems().get(0).getSkuName());
            stockBillLogExcelVO.setSpuName(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getStockBillLogItems().get(0).getSpuName());
            stockBillLogExcelVO.setPartyCode(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getStockBillLogItems().get(0).getPartyCode());
            stockBillLogExcelVO.setStockCount(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getStockBillLogItems().get(0).getStockCount());
            stockBillLogExcelVO.setUnitPrice(conversionPrices(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getStockBillLogItems().get(0).getUnitPrice().toString()));
            stockBillLogExcelVO.setStatusName(statusName);
            stockBillLogExcelVO.setTotalAmount(conversionPrices(stockBillLogItemMap.get(stockBillLogExcelVO.getStockBillLogId()).getTotalAmount().toString()));        }
        return stockBillLogExcelList;
    }

    /**
     * 转换金额格式
     *
     * @param num
     * @return
     */
    private String conversionPrices(String num) {
        if (StrUtil.isBlank(num)) {
            return num;
        }
        BigDecimal b1 = new BigDecimal(num);
        BigDecimal b2 = new BigDecimal(Constant.PRICE_MAGNIFICATION);
        double price = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
        return Double.toString(price);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveInfo(StockBillLogVO stockBillLogVO) {
        // mq幂等处理
        Query query = new Query();
        query.addCriteria(Criteria.where("stockBillNo").is(stockBillLogVO.getStockBillNo()));
        if(Objects.nonNull(mongoTemplate.findOne(query, MongoStockBillLogBO.class))){
            return;
        }
        Date now = new Date();
        // 校验部分信息
        this.checkInfo(stockBillLogVO);
        stockBillLogVO.setCreateTime(now);
        stockBillLogVO.setUpdateTime(now);

        stockBillLogVO.setStockBillNo(this.getStockBillNoByType(null, StockType.instance(stockBillLogVO.getType())));
        // 处理金额并对商品完成出入库操作
        this.processingAmountAndStock(stockBillLogVO);
        MongoStockBillLogBO mongoStockBillLogBO = mapperFacade.map(stockBillLogVO, MongoStockBillLogBO.class);
        if (Objects.nonNull(stockBillLogVO.getSourceOrderNo())) {
            mongoStockBillLogBO.setSourceOrderNo(stockBillLogVO.getSourceOrderNo().toString());
        }
        Long stockBillLogId = saveMongoStockBillLog(mongoStockBillLogBO);

        List<MongoStockBillLogItemBO> mongoStockBillLogItemList = mapperFacade.mapAsList(stockBillLogVO.getStockBillLogItems(), MongoStockBillLogItemBO.class);
        saveMongoStockBillLogItem(stockBillLogId, mongoStockBillLogItemList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateStockLogOfOrderList(List<SkuStockLockDTO> skuStockLockList, Integer stockBillType, Integer stockType) {
        if (CollUtil.isEmpty(skuStockLockList)) {
            return;
        }
        Date now = new Date();
        Map<Long, List<SkuStockLockDTO>> shopStockMap = skuStockLockList.stream().collect(Collectors.groupingBy(SkuStockLockDTO::getShopId));
        for (Long shopId : shopStockMap.keySet()) {
            SkuStockLockDTO skuStockLockDTO = shopStockMap.get(shopId).get(0);
            StockBillLog stockBillLog = this.getStockBillLog(
                    skuStockLockDTO.getShopId(),
                    null,
                    now,
                    stockBillType,
                    stockType,
                    this.getStockBillNoByType(null, StockType.instance(stockType)),
                    StockBillStatus.SUCCESS.value(),
                    skuStockLockDTO.getOrderId()
            );
            this.generateStockLogOfOrderItemList(shopStockMap.get(shopId), stockBillLog, false);
        }
    }

    @Override
    public void updateInfo(StockBillLogDTO stockBillLogDTO) {
        Date now = new Date();
        StockBillLogVO stockBillLogVO = mapperFacade.map(stockBillLogDTO, StockBillLogVO.class);
        this.checkInfo(stockBillLogVO);
        stockBillLogVO.setUpdateTime(now);
        this.processingAmountAndStock(stockBillLogVO);
        //更新出入库明细信息
        StockBillLog stockBillLog = mapperFacade.map(stockBillLogVO, StockBillLog.class);
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(stockBillLogDTO.getStockBillLogId()));
        Update update = getStockBillLogUpdateParam(stockBillLog);
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoStockBillLogBO.class);
        if (updateResult.getModifiedCount() < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        // 更新出入货商品信息项
        DeleteResult deleteItemResult = mongoTemplate.remove(new Query(Criteria.where("stockBillLogId").is(stockBillLog.getStockBillLogId())), MongoStockBillLogItemBO.class);
        if (deleteItemResult.getDeletedCount() < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        // 保存初始化商品项信息
        List<StockBillLogItem> stockBillLogItemList = stockBillLogDTO.getStockBillLogItems();
        if (CollUtil.isEmpty(stockBillLogItemList)) {
            return;
        }
        List<MongoStockBillLogItemBO> mongoStockBillLogItemList = mapperFacade.mapAsList(stockBillLogItemList, MongoStockBillLogItemBO.class);
        saveMongoStockBillLogItem(stockBillLogDTO.getStockBillLogId(), mongoStockBillLogItemList);
    }

    @Override
    public long countByOrderId(Long orderId, Integer type) {
        Query query = new Query();
        query.addCriteria(Criteria.where("sourceOrderNo").is(orderId));
        query.addCriteria(Criteria.where("type").is(type));
        return mongoTemplate.count(query,MongoStockBillLogBO.class);
    }

    private Criteria getLogCriteria(StockBillLogDTO stockBillLogDTO) {
        Criteria criteria = new Criteria();
        criteria.and("shopId").is(stockBillLogDTO.getShopId());
        if (Objects.nonNull(stockBillLogDTO.getCreateStartTime()) && Objects.nonNull(stockBillLogDTO.getCreateEndTime())) {
                    criteria.and("createTime").lte(stockBillLogDTO.getCreateEndTime()).gte(stockBillLogDTO.getCreateStartTime());
        }
        if (Objects.nonNull(stockBillLogDTO.getBusinessStartTime()) && Objects.nonNull(stockBillLogDTO.getBusinessEndTime())) {
            criteria.and("businessTime").lte(stockBillLogDTO.getBusinessEndTime()).gte(stockBillLogDTO.getBusinessStartTime());
        }
        if (Objects.nonNull(stockBillLogDTO.getSourceOrderNo()) && !Objects.equals(stockBillLogDTO.getSourceOrderNo(),"")) {
            // 模糊查询只支持字段属性是字符串
            criteria.and("sourceOrderNo").regex(Pattern.compile("^.*" + stockBillLogDTO.getSourceOrderNo() + ".*$", Pattern.CASE_INSENSITIVE));
        }
        if (StrUtil.isNotBlank(stockBillLogDTO.getStockBillNo())) {
            criteria.and("stockBillNo").regex(Pattern.compile("^.*" + stockBillLogDTO.getStockBillNo() + ".*$", Pattern.CASE_INSENSITIVE));
        }
        if (Objects.nonNull(stockBillLogDTO.getStockBillType()) && !Objects.equals(stockBillLogDTO.getStockBillType(), 0)) {
            criteria.and("stockBillType").is(stockBillLogDTO.getStockBillType());
        }
        if (Objects.nonNull(stockBillLogDTO.getType())) {
            criteria.and("type").is(stockBillLogDTO.getType());
        }
        if (Objects.nonNull(stockBillLogDTO.getStatus())) {
            criteria.and("status").is(stockBillLogDTO.getStatus());
        }
        if (StrUtil.isNotBlank(stockBillLogDTO.getMakerMobile())) {
            criteria.and("makerMobile").is(stockBillLogDTO.getMakerMobile());
        }
        if (Objects.nonNull(stockBillLogDTO.getEmployeeId())) {
            criteria.and("employeeId").is(stockBillLogDTO.getEmployeeId());
        }
        if(CollUtil.isNotEmpty(stockBillLogDTO.getStockBillLogIds())){
            criteria.and("stockBillLogId").in(stockBillLogDTO.getStockBillLogIds());
        }
        return criteria;
    }

    private Update getStockBillLogUpdateParam(StockBillLog stockBillLog) {
        Update update = new Update();
        if (Objects.nonNull(stockBillLog.getStockChangeReasonId())) {
            update.set("stockChangeReasonId", stockBillLog.getStockChangeReasonId());
        }
        if (Objects.nonNull(stockBillLog.getEmployeeId())) {
            update.set("employeeId", stockBillLog.getEmployeeId());
        }
        if (Objects.nonNull(stockBillLog.getStatus())) {
            update.set("status", stockBillLog.getStatus());
        }
        if (Objects.nonNull(stockBillLog.getBusinessTime())) {
            update.set("businessTime", stockBillLog.getBusinessTime());
        }
        if (Objects.nonNull(stockBillLog.getTotalCount())) {
            update.set("totalCount", stockBillLog.getTotalCount());
        }
        if (Objects.nonNull(stockBillLog.getTotalAmount())) {
            update.set("totalAmount", stockBillLog.getTotalAmount());
        }
        if (Objects.nonNull(stockBillLog.getQualifications())) {
            update.set("qualifications", stockBillLog.getQualifications());
        }
        if (Objects.nonNull(stockBillLog.getSupplierId())) {
            update.set("supplierId", stockBillLog.getSupplierId());
        }
        if (Objects.nonNull(stockBillLog.getRemark())) {
            update.set("remark", stockBillLog.getRemark());
        }
        if (Objects.nonNull(stockBillLog.getMakerMobile())) {
            update.set("makerMobile", stockBillLog.getMakerMobile());
        }
        return update;
    }

    private StockBillLog getStockBillLog(Long shopId, Long employeeId, Date businessTime, Integer stockBillLogType, Integer stockType, String stockBillNo, Integer status, Long sourceOrderNo) {
        Date now = new Date();
        StockBillLog stockBillLog = new StockBillLog();
        stockBillLog.setShopId(shopId);
        stockBillLog.setEmployeeId(employeeId);
        stockBillLog.setCreateTime(now);
        stockBillLog.setUpdateTime(now);
        stockBillLog.setBusinessTime(businessTime);
        stockBillLog.setStockBillType(stockBillLogType);
        stockBillLog.setType(stockType);
        stockBillLog.setStockBillNo(stockBillNo);
        stockBillLog.setStatus(status);
        stockBillLog.setSourceOrderNo(sourceOrderNo);
        return stockBillLog;
    }

    /**
     * 根据订单项完成库存明细信息的生成和保存
     *
     * @param stockLockList
     * @param stockBillLog
     * @param isRefundOrder
     */
    private void generateStockLogOfOrderItemList(List<SkuStockLockDTO> stockLockList, StockBillLog stockBillLog, Boolean isRefundOrder) {
        List<StockBillLogItem> stockBillLogItemList = new ArrayList<>();
        long totalAmount = 0L;
        Integer totalCount = 0;

        for (SkuStockLockDTO orderItem : stockLockList) {
            // 普通商品sku
            SkuVO sku = skuService.getSkuBySkuId(orderItem.getSkuId());
            SkuStock skuStock = skuStockService.getBySkuId(orderItem.getSkuId());
            // 删除的sku不再添加记录
            if (Objects.equals(sku.getStatus(), -1)) {
                continue;
            }
            StockBillLogItem stockBillLogItem = this.getStockBillLogItem(
                    orderItem.getSkuId(),
                    orderItem.getSpuId(),
                    sku.getPriceFee(),
                    isRefundOrder ? (orderItem.getStatus() == -1 ? orderItem.getCount() : orderItem.getStatus()) : orderItem.getCount(),
                    skuStock.getStock()
            );
            int count  = orderItem.getStatus() == -1 ? orderItem.getCount() : orderItem.getStatus();
            totalAmount = totalAmount + count * sku.getPriceFee();
            totalCount += isRefundOrder ? (orderItem.getStatus() == -1 ? orderItem.getCount() : orderItem.getStatus()) : orderItem.getCount();
            stockBillLogItemList.add(stockBillLogItem);
        }
        if (totalCount == 0) {
            return;
        }
        stockBillLog.setTotalAmount(totalAmount);
        stockBillLog.setTotalCount(totalCount);
        MongoStockBillLogBO mongoStockBillLogBO = mapperFacade.map(stockBillLog, MongoStockBillLogBO.class);
        mongoStockBillLogBO.setSourceOrderNo(stockBillLog.getSourceOrderNo().toString());
        Long stockBillLogId = saveMongoStockBillLog(mongoStockBillLogBO);
        // 保存初始化商品项信息
        if (CollUtil.isEmpty(stockBillLogItemList)) {
            return;
        }
        List<MongoStockBillLogItemBO> mongoStockBillLogItemList = mapperFacade.mapAsList(stockBillLogItemList, MongoStockBillLogItemBO.class);
        saveMongoStockBillLogItem(stockBillLogId, mongoStockBillLogItemList);
    }

    private void saveMongoStockBillLogItem(Long stockBillLogId, List<MongoStockBillLogItemBO> mongoStockBillLogItemList) {
        ServerResponseEntity<List<Long>> serverResponse = segmentFeignClient.batchGetSegmentId(DistributedIdKey.MALL4CLOUD_STOCK_BILL_LOG_ITEM, mongoStockBillLogItemList.size());
        if (!serverResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        List<Long> segmentIds = serverResponse.getData();
        for (int i = 0; i < mongoStockBillLogItemList.size(); i++) {
            MongoStockBillLogItemBO mongoStockBillLogItemBO = mongoStockBillLogItemList.get(i);
            mongoStockBillLogItemBO.setStockBillLogId(stockBillLogId);
            mongoStockBillLogItemBO.setStockBillLogItemId(segmentIds.get(i));
            mongoStockBillLogItemBO.setCreateTime(new Date());
            mongoStockBillLogItemBO.setUpdateTime(new Date());
        }
        // 保存出入货商品信息项
        mongoTemplate.insert(mongoStockBillLogItemList, MongoStockBillLogItemBO.class);
    }

    private Long saveMongoStockBillLog(MongoStockBillLogBO mongoStockBillLogBO) {
        ServerResponseEntity<Long> response = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_STOCK_BILL_LOG);
        if (!response.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long stockBillLogId = response.getData();
        mongoStockBillLogBO.setStockBillLogId(stockBillLogId);
        // 保存初始化明细信息
        mongoTemplate.insert(mongoStockBillLogBO);
        return stockBillLogId;
    }

    private StockBillLogItem getStockBillLogItem(Long skuId, Long prodId, Long unitPrice, Integer stockCount, Integer afterStock) {
        Date now = new Date();
        StockBillLogItem stockBillLogItem = new StockBillLogItem();
        stockBillLogItem.setSkuId(skuId);
        stockBillLogItem.setSpuId(prodId);
        stockBillLogItem.setCreateTime(now);
        stockBillLogItem.setUpdateTime(now);
        stockBillLogItem.setUnitPrice(unitPrice);
        stockBillLogItem.setStockCount(stockCount);
        stockBillLogItem.setAfterStock(afterStock);
        return stockBillLogItem;
    }

    /**
     * 校验出入库明细信息
     *
     * @param stockBillLog
     */
    private void checkInfo(StockBillLogVO stockBillLog) {
        if (CollUtil.isEmpty(stockBillLog.getStockBillLogItems())) {
            // 出入库商品项不能为空
            throw new LuckException("商品项不能为空");
        }
        if (Objects.nonNull(stockBillLog.getStockBillLogId())) {
            // 更新时校验
            MongoStockBillLogBO mongoStockBillLog = mongoTemplate.findById(stockBillLog.getStockBillLogId(), MongoStockBillLogBO.class);
            if (Objects.isNull(mongoStockBillLog)) {
                throw new LuckException("该出入库信息不存在");
            }
            if (!Objects.equals(stockBillLog.getShopId(), mongoStockBillLog.getShopId())) {
                throw new LuckException("当前出入库信息不属于你的店铺");
            }
            if (!Objects.equals(mongoStockBillLog.getStatus(), StockBillStatus.AWAIT_SUBMIT.value())) {
                throw new LuckException("当前信息已完成或已作废，无法继续修改，请刷新页面");
            }
            stockBillLog.setStockBillNo(mongoStockBillLog.getStockBillNo());
        }
    }

    private void processingAmountAndStock(StockBillLogVO stockBillLog) {
        List<StockBillLogItemVO> stockBillLogItems = stockBillLog.getStockBillLogItems();
        boolean flag = false;
        Integer totalCount = 0;
        long totalAmount = 0L;
        List<Long> spuIds = stockBillLogItems.stream().map(StockBillLogItemVO::getSpuId).collect(Collectors.toList());
        List<Long> skuIds = stockBillLogItems.stream().map(StockBillLogItemVO::getSkuId).collect(Collectors.toList());
        Map<Long, List<StockBillLogItemVO>> listMap = stockBillLogItems.stream().collect(Collectors.groupingBy(StockBillLogItemVO::getSpuId));
        if (Objects.equals(stockBillLog.getStockBillType(), StockBillType.PURCHASE_STORAGE.value())) {
            // 采购入库操作
//            Map<Long,Integer> spuStockMap = new HashMap<>(16);
            stockBillLog.setStatus(StockBillStatus.SUCCESS.value());
            Map<Long,Integer> skuStockMap = new HashMap<>(16);
            List<SkuStock> skuStockList = new ArrayList<>();
            List<SpuExtension> spuExtensionList = new ArrayList<>();
            for (StockBillLogItemVO stockBillLogItemVO : stockBillLogItems) {
                skuStockMap.put(stockBillLogItemVO.getSkuId(),stockBillLogItemVO.getStockCount());
            }
//            // 库存计算
//            for (Long spuId : listMap.keySet()) {
//                int totalStock = 0;
//                for (StockBillLogItemVO stockBillLogItemVO : listMap.get(spuId)) {
//                    SkuVO sku = new SkuVO();
//                    sku.setSpuId(spuId);
//                    sku.setOldSkuId(stockBillLogItemVO.getSkuId());
//                    sku.setStock(stockBillLogItemVO.getStockCount());
//                    skuList.add(sku);
//                    skuStockMap.put(stockBillLogItemVO.getSkuId(),stockBillLogItemVO.getStockCount());
//                    totalStock += sku.getStock();
//                }
//                spuStockMap.put(spuId,totalStock);
//            }
            List<SkuVO> skuDbList = skuMapper.listSkuPriceBySupplierSkuIds(skuIds);
            for (SkuVO skuVO : skuDbList) {
                if(!skuStockMap.containsKey(skuVO.getSupplierSkuId())){
                    continue;
                }
                Integer stock = skuStockMap.get(skuVO.getSupplierSkuId());
                SkuStock skuStock = new SkuStock();
                skuStock.setStock(stock);
                skuStock.setSkuId(skuVO.getSkuId());
                skuStockList.add(skuStock);
                SpuExtension spuExtension = new SpuExtension();
                spuExtension.setStock(stock);
                spuExtension.setSpuId(skuVO.getSpuId());
                spuExtensionList.add(spuExtension);
            }
            Map<Long, List<SpuExtension>> longListMap = spuExtensionList.stream().collect(Collectors.groupingBy(SpuExtension::getSpuId));
            List<SpuExtension> resultSpuExtensionList = new ArrayList<>();
            for (List<SpuExtension> value : longListMap.values()) {
                SpuExtension spuExtension = new SpuExtension();
                Integer stock = 0;
                for (SpuExtension extension : value) {
                    stock += extension.getStock();
                }
                spuExtension.setSpuId(value.get(0).getSpuId());
                spuExtension.setStock(stock);
                resultSpuExtensionList.add(spuExtension);
            }
            if(CollectionUtil.isNotEmpty(skuStockList)){
                skuStockMapper.batchUpdateSkuStocks(skuStockList);
                spuExtensionMapper.batchUpdateSpuStocks(resultSpuExtensionList);
            }
//            List<SpuVO> spuDbList = spuMapper.listSpuBySpuIds(spuIds);
//            for (SpuVO spuVO : spuDbList) {
//                // 供应商商品入库默认为下架状态
//                spuVO.setStatus(SpuStatus.OFF_SHELF.value());
//                spuVO.setOldSpuId(spuVO.getSpuId());
//                spuVO.setTotalStock(spuStockMap.get(spuVO.getOldSpuId()));
//            }
//            // 1.保存商品信息
//            spuMapper.saveBatch(spuDbList);
//            // 2.保存商品属性信息
//            spuAttrValueMapper.batchCopyOldSpuAttrValues(spuDbList);
//            // 3.国际化信息、商品详情
//            spuDetailMapper.batchCopyOldSpuDetail(spuDbList);
//            spuLangMapper.batchCopyOldSpuLang(spuDbList);
//            // 4.商品扩展信息
//            spuExtensionMapper.batchCopyOldSpuExtension(spuDbList);
//            // 5.保存sku信息
//            // 处理数据，保存库存、属性
//            skuMapper.batchCopySkuList(skuList);
//            skuLangMapper.batchCopySkuLang(skuList);
//            skuStockMapper.batchCopySkuStocks(skuList);
//            spuSkuAttrValueMapper.batchCopySpuSkuAttr(skuList);
//            // 6.更新品牌信息
//            brandMapper.batchUpdateSpuCount(brandIds);
//            List<SpuAndSkuVO> spuAndSkuVO = skuMapper.listSpuAndSkuBySkuIds(skuIds);
//            for (StockBillLogItemVO stockBillLogItem : stockBillLogItems) {
//                //TODO 更新商品与sku的库存
//
//                this.updateProdStock(stockBillLogItem.getSpuId(), stockBillLogItem.getSkuId(), Objects.equals(stockBillLog.getType(), StockType.OUT_OF_STOCK.value()) ? -stockBillLogItem.getStockCount() : stockBillLogItem.getStockCount());
//                stockBillLogItem.setAfterStock(stockBillLogItem.getAfterStock());
//            }
        } else {
            // 其他操作
            for (Long spuId : listMap.keySet()) {
                List<SkuDTO> skuDTOList = new ArrayList<>();
                for (StockBillLogItemVO stockBillLogItem : listMap.get(spuId)) {
                    // 其他出库或其他入库
                    if ((Objects.equals(stockBillLog.getStockBillType(), StockBillType.OTHER_STORAGE.value()) || Objects.equals(stockBillLog.getStockBillType(), StockBillType.OTHER_OUTBOUND.value())) && Objects.equals(stockBillLog.getStatus(), StockBillStatus.SUCCESS.value())) {
                        // 更新商品与sku的库存
                        this.updateProdStock(stockBillLogItem.getSpuId(), stockBillLogItem.getSkuId(), Objects.equals(stockBillLog.getType(), StockType.OUT_OF_STOCK.value()) ? -stockBillLogItem.getStockCount() : stockBillLogItem.getStockCount());
                    }
                    SkuVO skuDb = skuService.getSkuBySkuId(stockBillLogItem.getSkuId());
                    SkuStock skuStock = skuStockService.getBySkuId(stockBillLogItem.getSkuId());
                    SkuDTO skuDTO = new SkuDTO();
                    stockBillLogItem.setAfterStock(skuStock.getStock());
                    // 设置默认单价
                    stockBillLogItem.setUnitPrice(skuDb.getPriceFee());
                    // 累计总金额
                    totalAmount = (long) Arith.add(totalAmount, Arith.mul(stockBillLogItem.getStockCount().doubleValue(), skuDb.getPriceFee().doubleValue()));
                    // 累计总数量
                    totalCount += stockBillLogItem.getStockCount();
                    skuDTO.setSkuId(stockBillLogItem.getSkuId());
                    skuDTO.setChangeStock(Objects.equals(stockBillLog.getStockBillType(), StockBillType.OTHER_STORAGE.value()) ? stockBillLogItem.getStockCount() : -stockBillLogItem.getStockCount());
                    skuDTOList.add(skuDTO);
                }
                SpuDTO spuDTO = new SpuDTO();
                spuDTO.setSpuId(spuId);
                spuDTO.setSkuList(skuDTOList);
            }
            stockBillLog.setTotalCount(totalCount);
            stockBillLog.setTotalAmount(totalAmount);
        }
    }

    /**
     * 更新商品库存
     * @param spuId
     * @param skuId
     * @param changeCount
     */
    private void updateProdStock(Long spuId, Long skuId, Integer changeCount) {
        //更新商品与sku的库存
        Boolean flag = spuService.updateSpuAndSkuStock(spuId, skuId, changeCount);
        if(!flag){
            throw new LuckException("库存更新失败");
        }
        spuService.removeSpuCacheBySpuId(spuId);
    }

    /**
     * 根据类型生成出入库单号
     *
     * @param stockBillType
     * @return
     */
    private String getStockBillNoByType(StockBillType stockBillType, StockType stockType) {
        // 获取订单号
        ServerResponseEntity<Long> inStockResponse = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_PRODUCT_STOCK_IN);
        if (!inStockResponse.isSuccess()) {
            throw new LuckException(inStockResponse.getMsg());
        }
        // 获取订单号
        ServerResponseEntity<Long> outStockResponse = segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_PRODUCT_STOCK_OUT);
        if (!outStockResponse.isSuccess()) {
            throw new LuckException(outStockResponse.getMsg());
        }
        if (Objects.nonNull(stockBillType)) {
            switch (stockBillType) {
                case PURCHASE_STORAGE:
                case RETURN_STORAGE:
                case OTHER_STORAGE:
                case INITIALIZE:
                case ORDER_CANCEL:
                case EDIT_STORAGE:
                case PROFIT_STORAGE:
                    // 入库单号
                    return "IB" + inStockResponse.getData();
                case PURCHASE_OUTBOUND:
                case EDIT_OUTBOUND:
                case LOSS_OUTBOUND:
                case OTHER_OUTBOUND:
                    // 出库单号
                    return "OB" + outStockResponse.getData();
                default:
                    break;
            }
        }
        if (Objects.nonNull(stockType)) {
            switch (stockType) {
                case OUT_OF_STOCK:
                    // 出库单号
                    return "OB" + outStockResponse.getData();
                case WAREHOUSING:
                    // 入库单号
                    return "IB" + inStockResponse.getData();
                default:
                    break;
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void voided(Long shopId, Long stockBillLogId) {
        MongoStockBillLogBO stockBillLogBO = mongoTemplate.findById(stockBillLogId, MongoStockBillLogBO.class);
        if (Objects.isNull(stockBillLogBO) || !Objects.equals(stockBillLogBO.getStatus(), StockBillStatus.AWAIT_SUBMIT.value())) {
            throw new LuckException("当前数据不存在或状态已经发生改变，请刷新后重试");
        }
        if (!Objects.equals(shopId, stockBillLogBO.getShopId()) && !Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            throw new LuckException("当前数据不属于你的店铺");
        }
        StockBillLog stockBillLog = mapperFacade.map(stockBillLogBO, StockBillLog.class);
        stockBillLog.setStatus(StockBillStatus.ABOLISHED.value());
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(stockBillLog.getStockBillLogId()));
        Update update = getStockBillLogUpdateParam(stockBillLog);
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoStockBillLogBO.class);
        if (updateResult.getModifiedCount() < 1) {
            throw new LuckException("操作失败，请刷新后重试");
        }
    }

    private Criteria getItemCriteriaByParam(StockBillLogDTO stockBillLogDTO) {
        Criteria criteria = new Criteria();
        SpuSimpleBO spuSimpleBO = new SpuSimpleBO();
        spuSimpleBO.setLang(I18nMessage.getLang());
        if (StrUtil.isNotBlank(stockBillLogDTO.getProdKey())) {
            if (Objects.equals(stockBillLogDTO.getProdKeyType(), ProdKeyType.SPU_NAME.value())) {
                // 商品名称
                spuSimpleBO.setSpuName(stockBillLogDTO.getProdKey());
                List<SpuSimpleBO> spuList = spuService.listSimple(spuSimpleBO);
                List<Long> spuIds = spuList.stream().map(SpuSimpleBO::getSpuId).collect(Collectors.toList());
                criteria.and("stockBillLogItems.spuId").in(spuIds);
            } else if (Objects.equals(stockBillLogDTO.getProdKeyType(), ProdKeyType.PARTY_CODE.value())) {
                logger.info("通过商品编码查询库存流水，商品编码：{}", stockBillLogDTO.getProdKey());
                // 商品编码
                List<SkuVO> skuVoList = skuMapper.listSkuByPartyCodeAndShopId(stockBillLogDTO.getProdKey(), stockBillLogDTO.getShopId());
                // skuId
                List<Long> skuIdList = skuVoList.stream().map(SkuVO::getSkuId).collect(Collectors.toList());
                // 供应商skuId
                List<Long> supplierSkuIdList = skuVoList.stream().map(SkuVO::getSupplierSkuId).collect(Collectors.toList());
                skuIdList.addAll(supplierSkuIdList);
                criteria.and("stockBillLogItems.skuId").in(skuIdList);
            }
        }
        if (CollUtil.isNotEmpty(stockBillLogDTO.getStockBillLogItemIds())) {
            criteria.and("stockBillLogItems.stockBillLogItemId").in(stockBillLogDTO.getStockBillLogItemIds());
        }
        return criteria;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void generateStockLogOfTakeStock(StockBillLog stockBillLog, List<SkuDTO> skuDTOList) {
        if (CollUtil.isEmpty(skuDTOList)) {
            return;
        }
        Date now = new Date();
        stockBillLog.setCreateTime(now);
        stockBillLog.setUpdateTime(now);
        stockBillLog.setBusinessTime(now);
        stockBillLog.setStatus(StockBillStatus.SUCCESS.value());
        stockBillLog.setStockBillNo(this.getStockBillNoByType(StockBillType.instance(stockBillLog.getStockBillType()), null));
        stockBillLog.setType(Objects.equals(stockBillLog.getStockBillType(), StockBillType.LOSS_OUTBOUND.value()) ? StockType.OUT_OF_STOCK.value() : StockType.WAREHOUSING.value());
        // 构建库存日志商品列表，并统计总数量和总金额
        List<StockBillLogItem> stockBillLogItems = new ArrayList<>(16);
        Double totalAmount = 0.0;
        int totalCount = 0;
        if (CollUtil.isNotEmpty(skuDTOList)) {
            for (SkuDTO skuDTO : skuDTOList) {
                int changeStock = Math.abs(skuDTO.getChangeStock());
                StockBillLogItem stockBillLogItem = this.getStockBillLogItem(
                        skuDTO.getSkuId(),
                        skuDTO.getSpuId(),
                        skuDTO.getMarketPriceFee(),
                        changeStock,
                        skuDTO.getStock()
                );
                totalCount += changeStock;
                totalAmount = Arith.add(totalAmount, Arith.mul(skuDTO.getMarketPriceFee(), changeStock));
                stockBillLogItems.add(stockBillLogItem);
            }
        }
        stockBillLog.setTotalCount(totalCount);
        stockBillLog.setTotalAmount(totalAmount.longValue());
        // 保存初始化明细信息
        MongoStockBillLogBO mongoStockBillLogBO = new MongoStockBillLogBO();
        BeanUtils.copyProperties(stockBillLog, mongoStockBillLogBO);
        this.saveMongoStockBillLog(mongoStockBillLogBO);
        // 补充stockBillLogId，并保存初始化商品项信息
        if (CollectionUtil.isNotEmpty(stockBillLogItems)) {
            List<MongoStockBillLogItemBO> stockBillLogItemBOList = new ArrayList<>(stockBillLogItems.size());
            stockBillLogItems.forEach(s -> {
                MongoStockBillLogItemBO tempStockBillLogItemBO = new MongoStockBillLogItemBO();
                BeanUtils.copyProperties(s, tempStockBillLogItemBO);
                stockBillLogItemBOList.add(tempStockBillLogItemBO);
            });
            this.saveMongoStockBillLogItem(mongoStockBillLogBO.getStockBillLogId(), stockBillLogItemBOList);
        }
    }
}
